package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/gif"
	"image/jpeg"
	"image/png"
	"log"
	"math/rand"
	"os"
	"path/filepath"
	"sync"
	"time"
)

func ZoomAllDots(imgIo image.Image, walkHandler func(o image.Image, x int, y int, c color.Color)) error {

	if walkHandler == nil {
		return fmt.Errorf("walkHandler is NULL")
	}

	width := imgIo.Bounds().Dx()
	height := imgIo.Bounds().Dy()

	wg := &sync.WaitGroup{}

	for hi := 0; hi < height; hi++ {
		// use goroutine for each line
		wg.Add(1)
		func(hi int) {
			for wi := 0; wi < width; wi++ {
				walkHandler(imgIo, wi, hi, imgIo.At(wi, hi))
			}
			wg.Done()
		}(hi)
	}
	wg.Wait()

	return nil
}

func ImgToFile(img image.Image, outputFilePath string) {
	picFile2, err := os.Create(outputFilePath)
	if err != nil {
		fmt.Printf("when create file %s error:%v\n", outputFilePath, err)
		return
	}
	defer picFile2.Close()
	if err := png.Encode(picFile2, img); err != nil {
		fmt.Println("png.Encode error:", err)
	}

}

// 等高线文件模板 取垂直第一列的像素
var colorTplFile = "./image/color-tpl2.png"

func main() {

	inputPath := ""
	outputPath := ""
	var reverse = false

	flag.StringVar(&colorTplFile, "color-tpl", colorTplFile, "color template file path")

	flag.StringVar(&inputPath, "i", inputPath, "input path")
	flag.StringVar(&outputPath, "o", outputPath, "output path")
	flag.BoolVar(&reverse, "r", reverse, "reverse highland altitude")
	flag.Parse()
	rand.Seed(time.Now().UnixNano())

	if outputPath == "" {
		outputFileName := filepath.Base(inputPath)
		outputPath = "x-" + outputFileName
		if reverse {
			outputPath = "xr-" + outputFileName
		}
	}

	fOld, err := os.Open(inputPath)
	if err != nil {
		fmt.Printf("open:%s failed:%v+\n", inputPath, err)
		return
	}
	defer fOld.Close()

	var imgOld image.Image

	theExt := filepath.Ext(inputPath)
	switch theExt {
	case ".png":
		imgOld, err = png.Decode(fOld)
	case ".gif":
		imgOld, err = gif.Decode(fOld)
	case ".jpg", ".jpeg":
		imgOld, err = jpeg.Decode(fOld)
	default:
		fmt.Printf("ext(%s) not supported \n", theExt)
		return
	}

	// imgOld, err = png.Decode(fOld)
	if err != nil {
		fmt.Printf("png.Decode:%s failed:%v+\n", inputPath, err)
		return
	}

	width, height := imgOld.Bounds().Dx(), imgOld.Bounds().Dy()

	imgNew := image.NewRGBA(image.Rect(0, 0, width, height))

	colorTplColors := colorTpl(colorTplFile, 10)
	fmt.Printf("deep of colorTpl %s is %d\n", colorTplFile, len(colorTplColors))

	dotCounter := 0
	maxRGB := 0
	minRGB := 0xFFFF

	ZoomAllDots(imgOld, func(o image.Image, x int, y int, c color.Color) {
		dotCounter++
		oldR, oldG, oldB, _ := c.RGBA()
		// oldRGBidx := int(oldR+oldG+oldB) * len(colorTplColors) / (260 * 3)
		oldRGBidx := int(oldR+oldG+oldB) / 3 * len(colorTplColors) / 0xFFFF
		if reverse {
			oldRGBidx = int(0xFFFF-oldR+0xFFFF-oldG+0xFFFF-oldB) / 3 * len(colorTplColors) / 0xFFFF
		}
		if oldRGBidx >= len(colorTplColors) {
			oldRGBidx = len(colorTplColors) - 1
		}
		if oldRGBidx < 0 {
			oldRGBidx = 0
		}
		if minRGB > int(oldR+oldG+oldB) {
			minRGB = int(oldR + oldG + oldB)
		}
		if maxRGB < int(oldR+oldG+oldB) {
			maxRGB = int(oldR + oldG + oldB)
		}
		newColor := colorTplColors[oldRGBidx] //selColors(o, x, y, width, height, sideDots)
		imgNew.Set(x, y, newColor)
	})

	ImgToFile(imgNew, outputPath)
	fmt.Printf("dotCounter:%d max=%d min=%d\n", dotCounter, maxRGB, minRGB)
	fmt.Printf("outputfile: %s\n", outputPath)

}

/*返回颜色数组，下标越大颜色海拔越高*/
func colorTpl(colorTplFile string, colorTplStep int) []color.Color {
	var colorTplFileIo, _ = os.Open(colorTplFile)
	defer colorTplFileIo.Close()
	var colorTplPng, err = png.Decode(colorTplFileIo)

	if err != nil {
		log.Println("png.decode err when read colorTpl:", err)
		return nil
	}

	// 从colorTplStep以上的部分取
	theLen := colorTplPng.Bounds().Dy() - colorTplStep
	cs := make([]color.Color, theLen)
	for i := 0; i < theLen; i++ {
		cs[i] = colorTplPng.At(0, (theLen-i-1)-colorTplStep)
	}
	return cs
}
